#include <iostream>
#include "tinyxml2.h" 
using namespace tinyxml2;

int example_1()
{
    int xmlRet = 0;
    XMLDocument doc;

    /* 从文件加载xml */
    xmlRet = doc.LoadFile("./in.xml");
    if(tinyxml2::XML_SUCCESS != xmlRet)
    {
        std::cout<<"Fail to load file, ErrorID:"<<doc.ErrorID()<<std::endl;
    }

    /* 将xml保存到文件 */
    xmlRet = doc.SaveFile("out.xml");
    if(tinyxml2::XML_SUCCESS != xmlRet)
    {
        std::cout<<"Fail to save file, ErrorID:"<<doc.ErrorID()<<std::endl;
    }

    return doc.ErrorID();
}

int example_2()
{
    static const char* xml = "<element/>";
    XMLDocument doc;
    doc.Parse( xml );

    return doc.ErrorID();
}

int example_3()
{
    static const char* xml =
        "<?xml version=\"1.0\"?>"
        "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
        "<PLAY>"
        "<TITLE>A Midsummer Night's Dream</TITLE>"
        "</PLAY>";

    XMLDocument doc;
    doc.Parse( xml );

    XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
    const char* title = titleElement->GetText();
    printf( "Name of play (1): %s\n", title );

    XMLText* textNode = titleElement->FirstChild()->ToText();
    title = textNode->Value();
    printf( "Name of play (2): %s\n", title );

    return doc.ErrorID();
}

bool example_4()
{
    static const char* xml =
        "<information>"
        "    <attributeApproach v='2' />"
        "    <textApproach>"
        "        <v>2</v>"
        "    </textApproach>"
        "</information>";

    XMLDocument doc;
    doc.Parse( xml );

    int v0 = 0;
    int v1 = 0;

    XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
    attributeApproachElement->QueryIntAttribute( "v", &v0 );

    XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
    textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );

    printf( "Both values are the same: %d and %d\n", v0, v1 );

    return !doc.Error() && ( v0 == v1 );
}

int main(int argc, const char * argv[])
{
    example_1();
    example_2();
    example_3();
    example_4();

    /**
     * 创建xml
     */
    tinyxml2::XMLDocument doc;
    /* default:<?xml version="1.0" encoding="UTF-8"?> */
    tinyxml2::XMLDeclaration *declaration = doc.NewDeclaration();
    doc.InsertFirstChild(declaration);

    tinyxml2::XMLElement *Student = doc.NewElement("Student");
    Student->SetAttribute("sex", "male");
    doc.InsertEndChild(Student);

    tinyxml2::XMLElement *Name = doc.NewElement("Name");
    Name->InsertNewText("Tom");
    Student->InsertEndChild(Name);

    tinyxml2::XMLElement *Age = doc.NewElement("Age");
    Age->InsertNewText("8");
    Student->InsertEndChild(Age);

    tinyxml2::XMLElement *From = doc.NewElement("From");
    From->InsertNewText("China");
    Student->InsertEndChild(From);

    /**
     * xml转string
     */
    tinyxml2::XMLPrinter printer;
    doc.Print( &printer);

    std::string xmlStr = printer.CStr();
    std::cout<<"createxml:"<<std::endl<<xmlStr<<std::endl;

    /**
     * string转xml
     */
    tinyxml2::XMLDocument outDoc;
    int xmlRet = outDoc.Parse(xmlStr.c_str());
    if(tinyxml2::XML_SUCCESS != xmlRet)
    {
        std::cout<<"Fail to Parse xml, ErrorID:"<<outDoc.ErrorID()<<"str:"<<xmlStr<<std::endl;
        return outDoc.ErrorID();
    }

    /**
     * 解析xml
     */
    {
        /* 内容校验 */
        bool ret = true;
        ret = ret && outDoc.FirstChildElement("Student");
        ret = ret && outDoc.FirstChildElement("Student")->FirstChildElement("Name");
        ret = ret && outDoc.FirstChildElement("Student")->FirstChildElement("Age");
        ret = ret && outDoc.FirstChildElement("Student")->FirstChildElement("From");
        if(!ret)
        {
            std::cout<<"Xml parse err,xml:"<<xmlStr<<std::endl;
            return outDoc.ErrorID();
        }
        
        const char* pSex = NULL;
        outDoc.FirstChildElement("Student")->QueryStringAttribute("sex", &pSex);
        std::string name = outDoc.FirstChildElement("Student")->FirstChildElement("Name")->GetText();
        std::string age = outDoc.FirstChildElement("Student")->FirstChildElement("Age")->GetText();
        std::string from = outDoc.FirstChildElement("Student")->FirstChildElement("From")->GetText();

        std::cout<<"sex:"<<pSex<<std::endl;
        std::cout<<"name:"<<name<<std::endl;
        std::cout<<"age:"<<age<<std::endl;
        std::cout<<"from:"<<from<<std::endl;
    }

    return 0;
}
